home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / sound / sndplaydoublebuffer / _source / aiff.c next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  9.7 KB  |  249 lines

  1. /*
  2.     File:        AIFF.c
  3.  
  4.     Contains:    Routine demonstrating how to parse AIFF sound files.
  5.  
  6.     Written by: Mark Cookson    
  7.  
  8.     Copyright:    Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                 8/31/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                 
  21.  
  22. */
  23.  
  24. #include "MyAIFF.h"
  25.  
  26. /*
  27.     need to substitute this code where using long doubles
  28.  
  29. typedef struct myLongDouble {
  30.     double    firstHalf;
  31.     double    secondHalf;
  32. } myLongDouble;
  33.  
  34. */
  35.  
  36. /* Given an AIFF File gets the sample rate and other relavent pieces of information.
  37.    This has been modified from its orignal form found in the Develop 11 MultiBuffer source. */
  38. /*-----------------------------------------------------------------------*/
  39.         OSErr    ASoundGetAIFFHeader        (SoundInfoPtr theSoundInfo,
  40.                                         long *dataStart,
  41.                                         long *length)
  42. /*-----------------------------------------------------------------------*/
  43. {
  44.     ChunkTemplatePtr        chunkTemplate        = nil;            /* ...for ease of access */
  45.     unsigned long            type                = kInit;
  46.     long                    filePosition        = kInit,
  47.                             byteCount            = kInit;
  48.     Fixed                    sampleRate            = kInit;
  49.     unsigned short            chunkFlags            = kInit;        /* remember chunks we've seen */
  50.     OSErr                    err                    = noErr;
  51.     char                    chunkBuffer[kChunkBufferSize];
  52.  
  53.     *dataStart = kInit;
  54.  
  55.     /*  Parse the AIFF (or AIFC) header */
  56.  
  57.     do {
  58.         /*    Position ourselves at the beginning of the next chunk and read in
  59.             a hunk-o-data... */
  60.         err = SetFPos (theSoundInfo->refNum, fsFromStart, filePosition);
  61.         if (err != noErr) {
  62.             DebugPrint ("\pSetFPos failed!");
  63.             break;
  64.         }
  65.  
  66.         byteCount = kChunkBufferSize;
  67.         err = FSRead (theSoundInfo->refNum, &byteCount, chunkBuffer);                        /* read a chunk */
  68.         if ((err != noErr) && (err != eofErr)) {
  69.             DebugPrint ("\pFSRead failed!");
  70.             break;
  71.         }
  72.  
  73.         /*    Now, position the template over the data... */
  74.         chunkTemplate = (ChunkTemplatePtr) chunkBuffer;
  75.  
  76.         /* assume a failure and break out of the do {} while loop if the next case isn't found.
  77.            if the case is found and no other error is detected, then each case needs to set noErr */
  78.         err = badFileFormat;                                
  79.         switch (chunkTemplate->generic.ckID) {
  80.             case FORMID:                                                                    /* Format Version Chunk? */
  81.                 /*    make sure that this is a standard, noncompressed AIFF file. */
  82.                 if ((chunkFlags & kFORM) == false) {                                        /* see if this chunk already exists */
  83.                     chunkFlags |= kFORM;                                                    /* otherwise mark it found */
  84.                     *length = chunkTemplate->container.ckSize;
  85.                     filePosition += sizeof (ContainerChunk);        /* Can't use ckSize because it's the size of the file, not this header */
  86.                     type = chunkTemplate->container.formType;
  87.                     err = noErr;
  88.                 }
  89.                 break;
  90.             case FormatVersionID:                                                            /* Format Version Chunk? */
  91.                 if ((chunkFlags & kFormatVersion) == false) {                                /* see if this chunk already exists */
  92.                     chunkFlags |= kFormatVersion;                                            /* otherwise mark it found */
  93.                     filePosition += chunkTemplate->formatVersion.ckSize + kChunkHeaderSize;    /* calculate next chunk's position */
  94.                     if (chunkTemplate->formatVersion.timestamp != AIFCVersion1) {
  95.                         err = kUnknownFormat;
  96.                     }
  97.                     else {
  98.                         err = noErr;
  99.                     }
  100.                 }
  101.                 break;
  102.             case CommonID:
  103.                 if ((chunkFlags & kCommon) == false) {                                        /* see if this chunk already exists */
  104.                     long double        tempLD    = 0.0;
  105.  
  106.                     chunkFlags |= kCommon;                                                    /* otherwise mark it found */
  107.                     filePosition += chunkTemplate->common.ckSize + kChunkHeaderSize;        /* calculate next chunk's position */
  108.  
  109.                     #ifdef powerc
  110.                         x80told (&(chunkTemplate->common.sampleRate), &tempLD);
  111.                     #else
  112.                         tempLD = chunkTemplate->common.sampleRate;
  113.                     #endif
  114.                     sampleRate = ASoundLongDoubleToFix (tempLD);
  115.  
  116.                     if (type == AIFCID) { 
  117.                         err = SetupDBHeader    (theSoundInfo,
  118.                                             sampleRate,
  119.                                             chunkTemplate->common.sampleSize,
  120.                                             chunkTemplate->common.numChannels,
  121.                                             fixedCompression,
  122.                                             chunkTemplate->extCommon.compressionType);
  123.                         theSoundInfo->needsMasking = false;
  124.                     }
  125.                     else {
  126.                         err = SetupDBHeader    (theSoundInfo,
  127.                                             sampleRate,
  128.                                             chunkTemplate->common.sampleSize,
  129.                                             chunkTemplate->common.numChannels,
  130.                                             notCompressed,
  131.                                             NoneType);
  132.                         if (chunkTemplate->common.sampleSize == kSixteen) {
  133.                             theSoundInfo->needsMasking = false;
  134.                         }
  135.                         else {
  136.                             theSoundInfo->needsMasking = true;
  137.                         }
  138.                     }
  139.                 }
  140.                 break;
  141.             case SoundDataID:
  142.                 if ((chunkFlags & kSoundData) == false) {                                                /* see if this chunk already exists */
  143.  
  144.                     /*    Let's remember where the Sound Data starts, so we can find the position in the file later.
  145.                         The mark will be positioned at the beginning of the chunk, so move 16 bytes past to get past
  146.                         the header information to the data. */
  147.                     *dataStart = filePosition + 16;
  148.                     chunkFlags |= kSoundData;                                                            /* otherwise mark it found */
  149.                     filePosition += chunkTemplate->soundData.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  150.                     err = noErr;
  151.                 }
  152.                 break;
  153.             /*
  154.                 The following list of chunks we don't care about, so we'll just skip over them.
  155.             */
  156.             case MarkerID:
  157.                 if ((chunkFlags & kMarker) == false) {                                                    /* see if this chunk already exists */
  158.                     chunkFlags |= kMarker;                                                                /* otherwise mark it found */
  159.                     filePosition += chunkTemplate->marker.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  160.                     err = noErr;
  161.                 }
  162.                 break;
  163.             case CommentID:
  164.                 if ((chunkFlags & kComment) == false) {                                                    /* see if this chunk already exists */
  165.                     chunkFlags |= kComment;                                                                /* otherwise mark it found */
  166.                     filePosition += chunkTemplate->marker.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  167.                     err = noErr;
  168.                 }
  169.                 break;
  170.             case InstrumentID:
  171.                 if ((chunkFlags & kInstrument) == false) {                                                /* see if this chunk already exists */
  172.                     chunkFlags |= kInstrument;                                                            /* otherwise mark it found */
  173.                     filePosition += chunkTemplate->instrument.ckSize + kChunkHeaderSize;                /* calculate next chunk's position */
  174.                     err = noErr;
  175.                 }
  176.                 break;
  177.             case MIDIDataID:
  178.                 if ((chunkFlags & kMIDIData) == false) {                                                /* see if this chunk already exists */
  179.                     chunkFlags |= kMIDIData;                                                            /* otherwise mark it found */
  180.                     filePosition += chunkTemplate->midiData.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  181.                     err = noErr;
  182.                 }
  183.                 break;
  184.             case AudioRecordingID:
  185.                 if ((chunkFlags & kAudioRecording) == false) {                                            /* see if this chunk already exists */
  186.                     chunkFlags |= kAudioRecording;                                                        /* otherwise mark it found */
  187.                     filePosition += chunkTemplate->audioRecording.ckSize + kChunkHeaderSize;            /* calculate next chunk's position */
  188.                     err = noErr;
  189.                 }
  190.                 break;
  191.             case ApplicationSpecificID:
  192.                 if ((chunkFlags & kApplicationSpecific) == false) {                                        /* see if this chunk already exists */
  193.                     chunkFlags |= kApplicationSpecific;                                                    /* otherwise mark it found */
  194.                     filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  195.                     err = noErr;
  196.                 }
  197.                 break;
  198.             case NameID:
  199.                 if ((chunkFlags & kName) == false) {                                                    /* see if this chunk already exists */
  200.                     chunkFlags |= kName;                                                                /* otherwise mark it found */
  201.                     filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  202.                     err = noErr;
  203.                 }
  204.                 break;
  205.             case AuthorID:
  206.                 if ((chunkFlags & kAuthor) == false) {                                                    /* see if this chunk already exists */
  207.                     chunkFlags |= kAuthor;                                                                /* otherwise mark it found */
  208.                     filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  209.                     err = noErr;
  210.                 }
  211.                 break;
  212.             case CopyrightID:
  213.                 if ((chunkFlags & kCopyright) == false) {                                                /* see if this chunk already exists */
  214.                     chunkFlags |= kCopyright;                                                            /* otherwise mark it found */
  215.                     filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  216.                     err = noErr;
  217.                 }
  218.                 break;
  219.             case AnnotationID:
  220.                 if ((chunkFlags & kAnnotation) == false) {                                                /* see if this chunk already exists */
  221.                     chunkFlags |= kAnnotation;                                                            /* otherwise mark it found */
  222.                     filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize;                    /* calculate next chunk's position */
  223.                     err = noErr;
  224.                 }
  225.                 break;
  226.             default :                                                                                    /* Unrecognized?? croak. */
  227.                 DebugPrint ("\pran into an undefined chunk!!");
  228.  
  229.                 /*    If we hit an unrecognized chunk, clear chunkFlags to drop out of the loop
  230.                     with the assumed error code. */
  231.                 chunkFlags = kInit;
  232.                 break;
  233.         }
  234.  
  235.     /*    We're only done when the the FORM, FormatVersion, Common and Sound Data chunks.  This is only
  236.         true of this incarnation - your needs may vary, so you'll have to modify the following statement
  237.         accordingly...
  238.         I know, this clause is a pain in the ass:  what it really says is this:
  239.             As long as we have a FORM Chunk and we don't have all of the {Formatversion, Common, SoundData} chunks
  240.             keep going... AND we haven't gotten an error from the file system. */
  241.     } while (stillMoreDataToRead);
  242.  
  243.     if (err != noErr) {
  244.         DebugPrint ("\pError in ASoundGetAIFFHeader");
  245.     }
  246.  
  247.     return err;
  248. }
  249.